#include "xmppcore/resourcebindingnegotiant.h"
#include "xmppcore/iq.h"
#include "utils/uniqueid.h"
#include "xmppcore/errorparserfactory.h"
#include "xmppcore/errordetailsparserfactory.h"
#include "xmppcore/stanzaerror.h"
#include "xmppcore/iqparserfactory.h"

namespace yoohoo_xmppcore {

const ProtocolKey Jid::PROTOCOL_KEY = ProtocolKey("bind", "urn:ietf:params:xml:ns:xmpp-bind");

ResourceBindingParsingFactory::ResourceBindingParsingFactory() {
	registerParser(new ErrorParserFactory(Error::ErrorTypeStanza), ProtocolRelation(ProtocolKey::NULL_PROTOCOL_KEY, StanzaError::PROTOCOL_KEY));
	registerParser(new StanzaErrorDetailsParserFactory, ProtocolRelation(StanzaError::PROTOCOL_KEY, StanzaError::ERROR_DETAIL_PROTOCOL_KEY));
	registerParser(new IqParserFactory, ProtocolRelation(ProtocolKey::NULL_PROTOCOL_KEY, Iq::PROTOCOL_KEY));
	registerParser(new JidParserFactory, ProtocolRelation(Iq::PROTOCOL_KEY, Jid::PROTOCOL_KEY));
}

Jid::Jid(QString jid) : _jid(jid) {
}

Jid::Jid(Jid& other) {
	this->_jid = other._jid;
}
	
QString Jid::jid() {
	return _jid;
}
	
QString Jid::toXml() {
	return QString("<resource>%1</resource>").arg(_jid);
}

JidParser::JidParser() : _jid(0) {
}

XmppObject* JidParser::obj() {
	return _jid;
}

ProtocolKey JidParserFactory::protocolKey() {
	return Jid::PROTOCOL_KEY;
}

XmppParser* JidParserFactory::createParser() {
	return new JidParser;
}

bool JidParser::processAttributes(QString path, QList<ParsingAttribute> attributes) {
	if (attributes.size())
		return false;

	return true;
}

bool JidParser::processText(QString path, QString text) {
	if (path.indexOf('/') == -1) {
		_jid = new Jid(text);
	} else {
		return false;
	}

	return true;
}

ResourceBindingNegotiant::ResourceBindingNegotiant(Connector* connector, QString resource, QObject* parent) :
		Negotiant(connector, parent), _resource(resource) {
}

void ResourceBindingNegotiant::negotiate() {
	Iq iq;
	iq.setObj(new Jid(_resource));
	_id = yoohoo_utils::UniqueId::instance()->get();
	iq.setId(_id);
	iq.setIqType(Iq::IqTypeSet);
	
	write(iq.toXml());
}

void ResourceBindingNegotiant::connectorReceived(QString xml) {
	XmppElement* element = parsingFactory()->parse(xml);

	if (!element) {
		emit negotiationError(UnknownNegotiationProtocolError);
		delete element;

		return;
	}

	StanzaError* error = dynamic_cast<StanzaError*>(element);
	if (error) {
		if ("bad-request" == error->definedCondition()) {
			emit resourceBindingError(ForbiddenError);
		} else if ("not-allowed" == error->definedCondition()) {
			emit resourceBindingError(NotAllowedError);
		} else if ("conflict" == error->definedCondition()) {
			emit resourceBindingError(ConflictError);
		} else {
			emit negotiationError(UnknownNegotiationProtocolError);
		}

		delete error;
		return;
	}
	
	Iq* iq = dynamic_cast<Iq*>(element);
	if (!iq) {
		emit negotiationError(UnknownNegotiationProtocolError);
		delete element;

		return;
	}

	XmppObject* obj = iq->obj();
	if (!obj) {
		emit negotiationError(UnknownNegotiationProtocolError);
		delete iq;

		return;
	}

	Jid* jid = dynamic_cast<Jid*>(obj);
	if (!jid) {
		emit negotiationError(UnknownNegotiationProtocolError);
	} else {
		emit success(jid->jid());
	}

	delete iq;
}

XmppParsingFactory* ResourceBindingNegotiant::parsingFactory() const {
	static ResourceBindingParsingFactory parsingFactory;

	return &parsingFactory;
}

}
